#ifndef OSCILLOSCOPECANVAS_H
#define OSCILLOSCOPECANVAS_H

#include <QFrame>
#include <QPen>
#include <QBrush>
#include <QtCore/QTimer>

#include "SignalData.h"

namespace Ui {
    class OscilloscopeCanvas;
}

class QSettings;
class QScriptEngine;
class OscilloscopeCanvas : public QFrame
{
    typedef double sample_type;
    typedef SignalData<sample_type> signal_type;

    Q_OBJECT
//    Q_PROPERTY(QPen penGrid READ getPenGrid WRITE setPenGrid NOTIFY propertyChanged)
//    Q_PROPERTY(QPen penAxis READ getPenAxis WRITE setPenAxis NOTIFY propertyChanged)
//    Q_PROPERTY(QBrush brush READ getBrush WRITE setBrush NOTIFY propertyChanged)
//    Q_PROPERTY(bool antialiased READ getAntialiased WRITE setAntialiased NOTIFY propertyChanged)
//    Q_PROPERTY(QColor backgroundcolor READ getBackgrondColor WRITE setBackgrondColor NOTIFY propertyChanged)
//    Q_PROPERTY(int xOffset READ getOffsetX WRITE setOffsetX NOTIFY propertyChanged)
//    Q_PROPERTY(int yOffset READ getOffsetY WRITE setOffsetY NOTIFY propertyChanged)
//    Q_PROPERTY(int xScale READ getScaleX WRITE setScaleX NOTIFY propertyChanged)
//    Q_PROPERTY(int yScale READ getScaleY WRITE setScaleY NOTIFY propertyChanged)

public:
    explicit OscilloscopeCanvas(QWidget *parent = 0);
    ~OscilloscopeCanvas();

    void writeSettings(QSettings & settings) const;
    void readSettings(QSettings & settings);

    void setPenGrid(const QPen &pen);
    const QPen & getPenGrid() const { return m_penGrid; }
    QPen & getPenGrid() { return m_penGrid; }

    void setPenAxis(const QPen &pen);
    const QPen & getPenAxis() const { return m_penAxis; }
    QPen & getPenAxis() { return m_penAxis; }

    void setPenHud(const QPen &pen);
    const QPen & getPenHud() const { return m_hudPen; }
    QPen & getPenHud() { return m_hudPen; }

    void setBrush(const QBrush &brush);
    const QBrush & getBrush() const { return m_brush; }
    QBrush & getBrush() { return m_brush; }

    bool getAntialiased() const { return m_antialiased; }

    void setBackgrondColor(QColor color);
    QColor getBackgrondColor() const { return m_backgroundcolor; }

    QString getCode(int nSignal = -1) const;
    const QColor &getSignalColor(int nSignal = -1) const;

    int getOffsetX() const;
    int getOffsetY() const;
    int getScaleX() const;
    int getScaleY() const;
    bool getEnabledState(int nSignal = -1) const;
    bool getStoppedState(int nSignal = -1) const;

    double getFloatScaleX() const;
    double getFloatScaleY() const;
    int getCurrentSignal() const;
    int getSignalCount() const;

    void appendSample(sample_type sample, int nSignal = -1);

public slots:
    void evaluateCode(QScriptEngine * pScriptEngine);
    void setCode(const QString & code);
    void setOffsetX(int offset);
    void setOffsetY(int offset);
    void setScaleX(int scale);
    void setScaleY(int scale);
    void setSignalCount(int nSignal);
    void setCurrentSignal(int nSignal);
    void setEnabledState(bool bEnable, int nSignal = -1);
    void setStoppedState(bool bEnable, int nSignal = -1);
    void setAntialiased(bool antialiased);
    void setSignalColor(QColor color);
    void setFrameStepExp(int nExpFrame);

protected:
    bool event(QEvent *e);
    void mouseMoveEvent(QMouseEvent *e);
    void mousePressEvent( QMouseEvent *e );
    void mouseReleaseEvent( QMouseEvent *e );
    void mouseDoubleClickEvent( QMouseEvent *e );
    void wheelEvent( QWheelEvent * e );
    void closeEvent(QCloseEvent * e);

    void paintEvent(QPaintEvent *evt);
    void drawBackbuffer();
    void drawOscilloscope(QPainter * painter);
    void drawSignals(QPainter * painter);
    void drawSignal(QPainter * painter, int nSignal = -1);
    void drawGrid(QPainter * painter);
    void drawHud(QPainter * painter, QRect * fontRect = NULL);
    void onPropertyChanged(bool bForceRepaint = false);
    void resizeEvent(QResizeEvent * evt);

    QRect oscilloscopeWindow() const;
    double evaluateCode(QScriptEngine * pScriptEngine, int nSignal);

signals:
    void propertyChanged();
    void changedFloatScaleX(double scale);
    void changedFloatScaleY(double scale);
    void gridSpaceChangedX(int space);
    void gridSpaceChangedY(int space);

    void changedCode(const QString & code);
    void changedOffsetX(int offset);
    void changedOffsetY(int offset);
    void changedScaleX(int scale);
    void changedScaleY(int scale);
    void changedCurrentSignal(int nSignal);
    void changedEnabledState(bool bEnabled);
    void changedStoppedState(bool bEnabled);
    void changedSignalColor(QColor color);
    void changedFrameStepExp(int nExpFrames);

protected:
    
    QTimer m_timer;
    Ui::OscilloscopeCanvas *ui;

    QPixmap m_doubleBuffer;
    QRegion m_paintRegion; //< Invalid region outside the oscilloscope bitmap (overlay)

    QPen    m_penGrid;
    QPen    m_penAxis;
    QPen    m_hudPen;
    QBrush  m_brush;
    QColor  m_backgroundcolor;
    QFont   m_hudFont;
    QPoint  m_posCapturedMouse;
    QPoint  m_posCapturedOffset;
    QList< signal_type > m_signals;

    int m_iCurrentSignal;
    int m_frameStep; //< Milliseconds betwen draws
    //int m_frameStepCounter;

    bool m_antialiased;
    bool m_capturedMouse;
    bool m_bDrawBackBuffer;

    signal_type &getSignal(int nSignal = -1);
    const signal_type &getSignal(int nSignal = -1) const;

private:
    signal_type::container_type m_drawData;
};

QDataStream &operator<<(QDataStream &ds, const OscilloscopeCanvas &o);
QDataStream &operator>>(QDataStream &ds, OscilloscopeCanvas &o);

#endif // OSCILLOSCOPECANVAS_H
